﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.ComponentModel;

using Top.Api;
using Top.Api.Request;
using Top.Api.Response;
using Top.Api.Domain;
using Top.Api.Util;

using System.IO;

namespace TopApp.Library
{
    public class TradeDownload : BackgroundWorker
    {
        private ITopClient client;
        private Properties.Settings settings;

        private DateTime lastIncrementDownTime;

        private MainForm form;

        public TradeDownload(MainForm form)
        {

            settings = Properties.Settings.Default;
            client = new DefaultTopClient(settings.top_api_url, settings.top_app_key, settings.top_app_secret);

            this.WorkerReportsProgress = true;
            this.WorkerSupportsCancellation = true;

            this.form = form;

            this.lastIncrementDownTime = form.TradeDownload_Period_lasttime.Value;

            this.DoWork += download_init;
        }

        public void download_init(object sender, DoWorkEventArgs e)
        {
            #region 异步下载订单

            if (form.TradeDownload_Customization_checkBox_doinit.Checked)
            {

                TopatsTradesSoldGetRequest req = new TopatsTradesSoldGetRequest();

                req.Fields = "tid,status";

                req.StartTime = form.TradeDownload_Init_starttime_dateTimePicker.Value.ToString("yyyyMMdd");
                req.EndTime = form.TradeDownload_Init_endtime_dateTimePicker.Value.ToString("yyyyMMdd");

                this.ReportProgress(10, "开始异步下载过程，以获取时间段" + req.StartTime.ToString() + "至" + req.EndTime.ToString() + "所创建的订单…");

                TopatsTradesSoldGetResponse response = client.Execute(req, settings.top_session_key);

                long taskId = 0;

                if (response.IsError)
                {
                    if (response.SubErrCode == "isv.task-duplicate")
                    {
                        taskId = Convert.ToInt32(response.SubErrMsg.Split(new Char[] { '=' })[1]);
                        this.ReportProgress(10, "当前请求的异步任务在此之前已经请求过，" + response.SubErrMsg + "，开始进行任务执行结果查询…");
                    }
                    else
                    {
                        this.ReportProgress(10, "异步下载过程出错了，线程已退出。" + response.ErrMsg + response.ErrCode + response.SubErrCode + response.SubErrMsg);
                        return;
                    }
                }
                else
                {
                    taskId = response.Task.TaskId;
                    this.ReportProgress(10, response.Task.TaskId.ToString());
                }

                TopatsResultGetRequest task_req = new TopatsResultGetRequest();
                task_req.TaskId = taskId;
                TopatsResultGetResponse task_response = new TopatsResultGetResponse();

                task_response = client.Execute(task_req, settings.top_session_key);

                if (task_response.Task.Status != "done")
                {

                    do
                    {
                        this.ReportProgress(10, "异步任务还没完成，服务器正在处理，1分钟后将再次查询任务状态…");
                        Thread.Sleep(60 * 1000);
                        task_response = client.Execute(task_req, settings.top_session_key);
                    } while (task_response.Task.Status != "done");

                }

                this.ReportProgress(10, "异步任务已完成，开始下载服务器处理结果…");

                List<Trade> asyncTrades = this.taskDown(task_response.Task);


                this.ReportProgress(10, "异步任务共检查到交易共" + asyncTrades.Count.ToString() + "笔，开始把数据插入金蝶数据库过程…");

                this.saveTradesIntoKIS(asyncTrades);

                this.ReportProgress(10, "异步订单插入完成。");

                this.ReportProgress(10, "update fail trade count");
            }
            #endregion

            #region 同步下载今天的所有订单
            if (form.TradeDownload_Customization_checkBox_dotodaydown.Checked)
            {
                this.ReportProgress(10, "开始下载今天的订单…");

                List<Trade> todayTrades = this.todayDown();

                this.ReportProgress(10, "共检查到今天的交易共" + todayTrades.Count.ToString() + "笔，开始把数据插入金蝶数据库过程…");

                this.saveTradesIntoKIS(todayTrades);

                this.ReportProgress(10, "今天的订单插入完成。");

                this.ReportProgress(10, "update fail trade count");
            }
            #endregion

            #region 进入周期下载过程

            this.ReportProgress(10, "【" + DateTime.Now + "】开始进入周期增量下载过程，" + Properties.Settings.Default.trade_download_period_interval + "分钟后将进入第一个周期…");
            
            do{

                Thread.Sleep((Convert.ToInt32(Properties.Settings.Default.trade_download_period_interval) * 60 * 1000));

                this.ReportProgress(10,"启动次数加一");

                this.ReportProgress(10, "已进入新的增量下载周期…");
                List<Trade> incrementTrades = this.incrementDown();
                this.ReportProgress(10, "共检查到增量交易共" + incrementTrades.Count.ToString() + "笔，开始把数据插入金蝶数据库过程…");
                this.saveTradesIntoKIS(incrementTrades);
                this.ReportProgress(10, "增量交易订单插入过程已完成");

                // 失败订单重试
                if (form.TradeDownload_Period_doredown.Checked)
                {
                    this.ReportProgress(10, "开始重试已保存失败的订单…");
                    List<Trade> redownTrades = reDown();
                    this.ReportProgress(10, "共检查到已保存失败的订单共" + redownTrades.Count.ToString() + "笔，开始把数据插入金蝶数据库过程…");
                    this.saveTradesIntoKIS(redownTrades);
                    this.ReportProgress(10, "重试已保存失败的订单过程已完成");

                    this.ReportProgress(10, "update fail trade count");
                }

                this.ReportProgress(10, "【"+DateTime.Now+"】本周期已完成，" + Properties.Settings.Default.trade_download_period_interval.ToString() + "分钟后将进入下一个周期…");

            }while(true);

            #endregion

        }

        #region 三个订单下载过程的执行函数（返回订单集合）
        // 下载异步任务（今天以前数天内的所有订单）的结果
        private List<Trade> taskDown(Task task)
        {
            //初始化数据目录
            string path = "task_file/" + task.TaskId.ToString();
            if (!Directory.Exists(path)) Directory.CreateDirectory(path);
            string path_unzip = path + "/unzip";
            if (!Directory.Exists(path_unzip)) Directory.CreateDirectory(path_unzip);

            string taskFile = AtsUtils.Download(task.DownloadUrl,path); // 下载文件到本地
            List<string> trade_files = AtsUtils.Unzip(taskFile, path_unzip);

            List<Trade> trades = new List<Trade>();

            foreach (string file in trade_files)
            {
                using (StreamReader reader = new StreamReader(file))
                {
                    string line = null;
                    while ((line = reader.ReadLine()) != null)
                    {
                        TradeFullinfoGetResponse rsp = TopUtils.ParseResponse<TradeFullinfoGetResponse>(line);
                        trades.Add(rsp.Trade);
                    }
                }
            }

            return trades;
        }

        // 下载今天的所有订单
        private List<Trade> todayDown()
        {
            TradesSoldGetRequest req = new TradesSoldGetRequest();
            req.Fields = "tid,status";
            req.StartCreated = DateTime.Today;
            req.EndCreated = lastIncrementDownTime = DateTime.Now;
            this.ReportProgress(22, lastIncrementDownTime); //记录最后周期结尾时间点
            req.PageSize = 100L;
            req.UseHasNext = true;

            this.ReportProgress(10, "正在下载" + req.StartCreated.ToString() + "至" + req.EndCreated.ToString()+"所创建的订单");

            long pageNo = 1L;
            TradesSoldGetResponse rsp = null;

            List<Trade> trades = new List<Trade>();

            do
            {
                req.PageNo = pageNo;
                rsp = client.Execute(req, settings.top_session_key);
                if (!rsp.IsError)
                {
                    this.ReportProgress(10,"正在下载第" + req.PageNo + "页");
                    foreach (Trade trade in rsp.Trades)
                    {
                        trades.Add(trade);
                    }
                    pageNo++;
                }
            } while (rsp != null && (rsp.IsError || rsp.HasNext));

            return trades;
        }

        // 下载增量订单
        private List<Trade> incrementDown()
        {
            TradesSoldIncrementGetRequest req = new TradesSoldIncrementGetRequest();
            req.Fields = "tid,status";

            if (lastIncrementDownTime == null) lastIncrementDownTime = DateTime.Now;
            
            req.StartModified = lastIncrementDownTime;
            req.EndModified = lastIncrementDownTime = DateTime.Now; 
            
            this.ReportProgress(22, lastIncrementDownTime); //记录最后周期结尾时间点

            req.PageSize = 100L;
            req.UseHasNext = false;

            List<Trade> trades = new List<Trade>();

            this.ReportProgress(10, "周期：" + req.StartModified.ToString() + "到" + req.EndModified.ToString());

            TradesSoldIncrementGetResponse rsp = client.Execute(req, settings.top_session_key);
            if (!rsp.IsError)
            {
                long pageCount = ((rsp.TotalResults + req.PageSize - 1) / req.PageSize).Value;
                while (pageCount > 0)
                {
                    req.PageNo = pageCount;
                    req.UseHasNext = true;
                    rsp = client.Execute(req, settings.top_session_key);
                    if (!rsp.IsError)
                    {
                        this.ReportProgress(10, "正在下载第" + req.PageNo + "页");
                        foreach (Trade trade in rsp.Trades)
                        {
                            trades.Add(trade);
                        }
                        pageCount--;
                    }
                }
            }

            return trades;
        }

        // 重试下载未成功的订单
        private List<Trade> reDown()
        {
            List<Trade> trades = new List<Trade>();

            AppDataBase appdata = new AppDataBase();
            List<long> tradeIds = appdata.getFailTradeIds();

            foreach (long trade_id in tradeIds)
            {
                Trade trade = new Trade();
                trade.Tid = trade_id;
                trade.Status = "SAVE_FAILED";

                trades.Add(trade);
            }

            return trades;
        }
        #endregion

        private int saveTradesIntoKIS( List<Trade> trades )
        {
            KISInterface kis = new KISInterface();
            AppDataBase appdata = new AppDataBase();
            int index = 0;
            foreach (Trade trade in trades){

                index++;

                if (trade.Status == "WAIT_SELLER_SEND_GOODS" || trade.Status == "WAIT_BUYER_CONFIRM_GOODS" || trade.Status == "TRADE_FINISHED" || trade.Status == "TRADE_CLOSED" || trade.Status == "SAVE_FAILED")
                {
                    string expNo = ""; //MessageBox.Show(trade.Status);
                    if (trade.Status != "WAIT_SELLER_SEND_GOODS" || trade.Status != "TRADE_CLOSED")
                    {
                        expNo = this.getOrderExpressBillNo(trade.Tid);
                    }
                    //MessageBox.Show(expNo);
                    Trade fullTrade = this.getFullTrade(trade.Tid);

                    Boolean b = false;

                    if (trade.Status == "TRADE_CLOSED")
                    {
                        try
                        {
                            b = kis.deleteStockBill(trade);
                        }
                        catch (Exception e)
                        {
                            this.ReportProgress(10, e.Message);
                            throw e;
                        }
                    }
                    else
                    {

                        try
                        {
                            b = kis.saveTrade(fullTrade, expNo);
                        }
                        catch (Exception e)
                        {
                            this.ReportProgress(10, e.Message);
                            throw e;
                        }
                    }

                    if (b)
                    {
                        //如果是重试的订单，则删除数据库记录 something must be do here
                        if (trade.Status == "SAVE_FAILED")
                        {
                            appdata.deleteFailTrade(trade.Tid);
                        }

                        if (trade.Status == "TRADE_CLOSED")
                        {
                            this.ReportProgress(10, "[" + index + "]已退款订单【" + trade.Tid.ToString() + "】删除成功…");
                        }
                        else
                        {

                            this.ReportProgress(10, "[" + index + "]保存订单【" + trade.Tid.ToString() + "】成功…");

                        }
                    }
                    else
                    {
                        if (trade.Status == "TRADE_CLOSED")
                        {
                            this.ReportProgress(10, "[" + index + "]已退款订单【" + trade.Tid.ToString() + "】删除失败…");
                        }
                        else
                        {

                            this.ReportProgress(10, "[" + index + "]保存订单【" + trade.Tid.ToString() + "】失败了！因为：" + kis.errMsg);
                        }

                        kis.AppDB.insertFailTrade(trade.Tid, kis.errMsg);

                        this.ReportProgress(10, "update fail trade count");
                    }
                }
                else
                {
                    this.ReportProgress(10, "[" + index + "]订单【" + trade.Tid.ToString() + "】状态为【" + trade.Status + "】不符合要求，已跳过…");
                }

                Thread.Sleep(500); // 太快容易产生网络及数据库异常，所以等半秒再执行下一个订单的处理
            }

            return trades.Count;
        }

        public Trade getFullTrade(long trade_id)
        {
            TradeFullinfoGetRequest req = new TradeFullinfoGetRequest();
            req.Fields = "tid,buyer_nick,seller_memo,created,pay_time,modified,orders,post_fee";
            req.Tid = trade_id;

            TradeFullinfoGetResponse response = client.Execute(req, settings.top_session_key);

            if (response.IsError)
            {
                string msg = "获取订单[" + req.Tid.ToString() + "]失败，错误代码：" + response.ErrCode + " " + response.ErrMsg;
                this.ReportProgress(10, msg);
                return getFullTrade(trade_id);
            }
            else
            {
                this.ReportProgress(10, "获取订单[" + req.Tid.ToString() + "]成功，正在处理……");
                return response.Trade;
            }

        }

        public string getOrderExpressBillNo(long Tid)
        {
            LogisticsOrdersGetRequest req = new LogisticsOrdersGetRequest();
            req.Fields = "out_sid";
            req.Tid = Tid;
            req.PageNo = 1L;
            req.PageSize = 40L;

            LogisticsOrdersGetResponse response = client.Execute(req, settings.top_session_key);
            string expressbill = "";
            int ss = response.Shippings.Count;
            //MessageBox.Show(ss.ToString());
            if (ss > 0)
            {
                expressbill = response.Shippings[0].OutSid;
                //MessageBox.Show(expressbill);
            }
            else
            {
                expressbill = "";
            }
            return expressbill;
        }

    }
}
